import java.util.Arrays;
import java.util.Vector;

import org.joda.time.DateTime;

//@author: Mengdi A0105699R
class Command { 
	private static final int NUM_CMD_TYPE                    = 21;
	private static final int NUM_WEEKDAY                     = 14;
	private static final String[] DAYS_OF_WEEK               = {
		"monday","tuesday","wednesday","thursday","friday","saturday","sunday",
		"mon", "tue", "wed", "thu", "fri","sat","sun"
	};
	private static final String[] TODAY_OR_TMR       = {
		"today","tmr","tomorrow"
	};
	private static final String[] CMD_TYPE_STRINGS   = {
		"add", "ad", "+",
		"del", "delete", "-",
		"mark","mk", "m", "*",
		"unmark", "um","~",
		"edit",
		"help",
		"clear",
		"display",
		"undo",
		"search",
		"show",
		"exit"
	};
	private static final CommandType[] CMD_TYPE_LIST = {
		CommandType.ADD, CommandType.ADD, CommandType.ADD,
		CommandType.DELETE, CommandType.DELETE, CommandType.DELETE,
		CommandType.MARK, CommandType.MARK, CommandType.MARK, CommandType.MARK,
		CommandType.UNMARK, CommandType.UNMARK, CommandType.UNMARK,
		CommandType.EDIT,
		CommandType.HELP,                                                                                               
		CommandType.CLEAR,
		CommandType.DISPLAY,
		CommandType.UNDO,
		CommandType.SEARCH,
		CommandType.SHOW,
		CommandType.EXIT,
		CommandType.INVALID,
	};
	private static final String[] KEYWORD_BY           = {" /by "," by "};
	private static final String[] KEYWORD_TO           = {" /to "," to "};
	private static final String[] KEYWORD_IN           = {" /in "," in "};
	private static final String[] KEYWORD_FROM         = {" /from ", " from "};
	private static final String NOT_DEADLINED_TASK = "not deadline";

	private static final DateTime FLOATING_DEADLINE  = new DateTime(9999,12,31,23,59,0,0);

	private static final DateTime MIN_DATETIME = new DateTime(0);
	private static final DateTime MAX_DATETIME = FLOATING_DEADLINE;
	private static final DateTime[] floating = {MIN_DATETIME, MAX_DATETIME};
	private static final Vector<DateTime> FLOATING = new Vector<DateTime>(Arrays.asList(floating));

	private String userCommand;
	private String[] commandTokens;
	private int numTokens;
	private CommandType cmdType;
	private int TypeIndex;
	private boolean onlyDate;
	public Vector<DateTime> range;

	public Command (String cmdString) {
		// Store user command, command tokens, number of tokens
		userCommand = cmdString;
		commandTokens = cmdString.split("\\s+");
		numTokens = commandTokens.length;
		range = new Vector<DateTime>();
		onlyDate = false;

		// Determine command type. INVALID if no match.
		String cmdTypeString = commandTokens[0];
		cmdType = CommandType.INVALID;
		for (int i = 0; i < NUM_CMD_TYPE; i++) {
			if (cmdTypeString.equalsIgnoreCase(CMD_TYPE_STRINGS[i])) {
				cmdType = CMD_TYPE_LIST[i];
				TypeIndex = i;
				break;
			}
		}
		if ((commandTokens.length == 1)&&(cmdType != CommandType.CLEAR)
				&&(cmdType!=CommandType.UNDO)){
			cmdType = CommandType.INVALID;
		}
		setDateTime();
	}

	public Vector<DateTime> getDateTime() {
		return range;
	}

	public CommandType getCmdType() {
		return cmdType;
	}
	public int getCmdTypeLength(){
		return CMD_TYPE_STRINGS[TypeIndex].length();
	}
	public String getDescription() {
		switch (cmdType) {
		case ADD:
			return getAddDescription();

		case EDIT:
			return getEditDescription();

		default:
			return null;
		}
	}


	private String getAddDescription() {
		int startIndex = getCmdTypeLength() + 1;
		String wholeSentence = userCommand.substring(startIndex);
		if (!getDescriptionWithBYIN(wholeSentence).equals(NOT_DEADLINED_TASK)){
			return getDescriptionWithBYIN(wholeSentence); 
		}
		else {
			return getDescriptionWithFROMTO(wholeSentence);
		}

	}    

	private String getEditDescription() {

		String firstWord = commandTokens[2];
		int startIndex = userCommand.indexOf(firstWord);
		String sentence = userCommand.substring(startIndex);
		if (!getDescriptionWithBYIN(sentence).equals(NOT_DEADLINED_TASK)){
			return getDescriptionWithBYIN(sentence);
		}
		else {
			return getDescriptionWithFROMTO(sentence);
		}
	} 


	private String getDescriptionWithBYIN(String sentence){

		String[] splitByKeywordBY = splitByKeyword(KEYWORD_BY, sentence);
		String[] splitByKeywordIN = splitByKeyword(KEYWORD_IN, sentence);

		if (splitByKeywordBY.length!=1){
			return checkWithKeywordBY(splitByKeywordBY,sentence);
		}
		else {
			return checkWithKeywordIN(splitByKeywordIN, sentence);
		}

	}
	private String checkWithKeywordBY(String[] splitByKeywordBY, String sentence){
		String[] splitByKeywordIN = splitByKeyword(KEYWORD_IN, sentence);
		String wholeSentence = sentence.trim();
		if (splitByKeywordBY.length > 2) {
			if (sentence.contains(KEYWORD_BY[0])){ //multiple /by
				return null;
			}
			else if (sentence.contains("from")){ //multiple by but 'from' is the keyword
				return NOT_DEADLINED_TASK;
			}
			else {
				return wholeSentence; //multiple by, no keyword
			}
		}		   	    
		if(splitByKeywordBY.length == 2){ //one keyword by
			return checkWithOneKeywordBY(splitByKeywordBY,sentence);		    	
		}

		return checkWithKeywordIN(splitByKeywordIN,sentence);		    			
	}

	private String checkWithOneKeywordBY(String[] splitByKeywordBY, String sentence){

		String wholeSentence = sentence.trim();
		String[] tempTokens = splitByKeywordBY[1].trim().split("\\s+");
		int size = tempTokens.length;
		if (size > 2){
			if (contain(tempTokens, "from")){// from is the keyword
				return NOT_DEADLINED_TASK;
			}
			else if (contain(tempTokens, "next")){
				if (getDateTimeWithNext(tempTokens).compareTo(FLOATING_DEADLINE) == 0){
					return wholeSentence; //floating task, next is not a keyword
				}
				else {
					return splitByKeywordBY[0].trim();//by is a keyword with keyword next
				}
			}
			else if ((contain(tempTokens, "in")||(contain(tempTokens, "/in")))){//after by,in also appear
				int index = wholeSentence.indexOf("by");
				String[] futureTime = splitByKeyword(KEYWORD_IN, wholeSentence.substring(index));//after by
				if (futureTime.length > 2){//multiple in
					if (contain(tempTokens, KEYWORD_IN[0])){
						return null;
					}
					else {
						return wholeSentence;
					}
				}
				if(futureTime.length == 2){//only one in
					if (inFutureTime(futureTime[1]).equals(FLOATING_DEADLINE)){//in is not keyword
						return wholeSentence;
					}
					else {
						String[] splitByKeywordIN = splitByKeyword(KEYWORD_IN, sentence);
						return splitByKeywordIN[0];//before in is the description
					}
				}
			}
			else {// doesn't contain from, next or in, but size> 2, floating task
				return wholeSentence;
			}
		}
		else if (size == 2){
			if (contain(tempTokens, "next")){
				if(getDateFromWeekday(tempTokens[1])!=null){
					return splitByKeywordBY[0].trim();//for format "next tue"
				}
				else {
					return wholeSentence;//next is not a keyword
				}
			}	    				    		
			if (getDateTimeFrom2Tokens(tempTokens).compareTo(FLOATING_DEADLINE)!= 0){
				return splitByKeywordBY[0].trim();// for format T+D or D+T
			}
			else {	    			
				return wholeSentence;// the 2 tokens are not datetime, floating task
			}
		}
		else {// size == 1
			if (getDateTimeFrom1Token(tempTokens[0]).compareTo(FLOATING_DEADLINE) != 0){
				return splitByKeywordBY[0].trim();
			}
			else{	                
				return wholeSentence;
			}
		}
		return wholeSentence;

	}
	private String checkWithKeywordIN(String[] splitByKeywordIN, String sentence){
		String wholeSentence = sentence.trim();
		if(splitByKeywordIN.length >2){
			if (sentence.contains(KEYWORD_IN[0])){//multiple /in
				return null;
			}
			else {
				return wholeSentence;
			}
		}
		if(splitByKeywordIN.length == 2){
			if (inFutureTime(splitByKeywordIN[1]).compareTo(FLOATING_DEADLINE)== 0){
				return wholeSentence; // in is not a keyword, floating task
			}
			else{
				return splitByKeywordIN[0].trim(); // in is a keyword
			}
		}
		return NOT_DEADLINED_TASK; //it doesn't contain in and by(as checked previously)

	}
	private String getDescriptionWithFROMTO(String wholeSentence){
		if (getStartEndTime()== null){
			return null;// wrong format, then invalid command
		}
		else if (getStartEndTime().equals(FLOATING)){
			return wholeSentence; // no time extracted, floating task
		}
		else {
			String[] splitByKeywordFROM = splitByKeyword(KEYWORD_FROM,wholeSentence);
			return splitByKeywordFROM[0];//timed task, description is before 'from'
		}
	}
	public Vector<String> getSearchKeywords(){
		if(cmdType == CommandType.SEARCH){
			String keywords = userCommand.substring(getCmdTypeLength()).trim();
			String[] keywordTokens = keywords.split("\\s+");

			return new Vector<String>(Arrays.asList(keywordTokens));// a vector of keywords
		}
		else{
			return null;
		}

	}
	public DateTime getShowDateTime(){
		if(cmdType == CommandType.SHOW){
			String datetime = userCommand.substring(getCmdTypeLength()).trim();
			String[] tempTokens = datetime.split("\\s+");
			if(tempTokens.length == 2){
				DateTime showFrom2Token = getDateTimeFrom2Tokens(tempTokens);
				if ((showFrom2Token.equals(FLOATING_DEADLINE))||(showFrom2Token==null)){
					return null;
				}
				else {
					return showFrom2Token;
				}
			}
			else if (tempTokens.length == 1){
				String token = tempTokens[0];
				DateTime showFrom1Token = getDateTimeFrom1Token(token);
				if ((showFrom1Token.equals(FLOATING_DEADLINE))||(showFrom1Token == null)){
					return null;
				}
				else {
					return showFrom1Token;
				}
			}
			else{
				return null;
			}
		}
		else{
			return null;
		}
	}

	public Vector <Integer> getIndexList() {
		switch (cmdType) {
		case DELETE:
		case MARK:
		case UNMARK:
			return getIndexListOfDeleteMarkUnmark();

		default:
			return null;
		}

	}
	private Vector <Integer> getIndexListOfDeleteMarkUnmark() {
		try {
			Vector <Integer> indexList = new Vector <Integer> (); 
			for (int i = 1; i < numTokens; i++) {
				int numIndex = Integer.parseInt(commandTokens[i]);
				indexList.add(numIndex - 1);
			}        
			return indexList;
		} catch (NumberFormatException e) {
			return null;
		}
	}
	public int getEditIndex(){
		if (isNumeric(commandTokens[1])){
			return Integer.parseInt(commandTokens[1])-1;
		}
		else {
			return -1;//there is no number
		}
	}
	private static boolean isNumeric(String str){ 
		try{
			Integer.parseInt(str);
		}
		catch(NumberFormatException nfe){
			return false;  
		}  
		return true;  
	}


	//if return null, invalid command
	//if return floating, floating task
	public Vector<DateTime> getStartEndTime(){
		String[] splitByKeywordFROM = splitByKeyword(KEYWORD_FROM, userCommand);

		if (splitByKeywordFROM.length > 2){
			if (userCommand.contains(KEYWORD_FROM[0])){
				return null;
			}
			else {//it just contain two or more normal from
				return FLOATING;
			}
		}
		if (splitByKeywordFROM.length == 2){
			String[] splitByKeywordTO = splitByKeyword(KEYWORD_TO,splitByKeywordFROM[1]);
			if (splitByKeywordTO.length > 2){
				if (userCommand.contains(KEYWORD_TO[0])){
					return null;
				}
				else {// it just contains two or more to
					return FLOATING;
				}
			}
			else if (splitByKeywordTO.length == 2){
				String startTime = splitByKeywordTO[0];
				String[] startTokens = startTime.split("\\s+");
				String endTime = splitByKeywordTO[1];
				String[] endTokens = endTime.split("\\s+");
				return getVectorForTimedTask(startTokens,endTokens);
			}
			else {//it doesn't contain to but contain from
				return null;

			}

		}
		return FLOATING; // it doesn't contain from

	}
	private Vector<DateTime> getVectorForTimedTask(String[] startTokens, String[] endTokens){
		Vector<DateTime> startEnd = new Vector<DateTime>();
		if (startTokens.length > 2){
			if (getDateTimeWithNext(startTokens).compareTo(FLOATING_DEADLINE)== 0){//not time
				startEnd.add(MIN_DATETIME);
			}
			else {
				startEnd.add(getDateTimeWithNext(startTokens));
			}
		}
		else if (startTokens.length == 2){
			if (getDateTimeWithNext(startTokens).compareTo(FLOATING_DEADLINE)!=0){
				startEnd.add(getDateTimeWithNext(startTokens));
			}
			else if (getDateTimeFrom2Tokens(startTokens) == null){
				startEnd.add(MIN_DATETIME);
			}
			else {
				startEnd.add(getDateTimeFrom2Tokens(startTokens));
			}
		}
		else {
			String start = startTokens[0];
			DateTime result = getDateTimeFrom1Token(start);
			if (result == null || result.equals(FLOATING_DEADLINE)){//attention!!
				startEnd.add(MIN_DATETIME);
			}
			else {
				startEnd.add(result);
			}
		}
		if (endTokens.length > 2){
			if (getDateTimeWithNext(endTokens).equals(FLOATING_DEADLINE)){
				return FLOATING;
			}
			else {
				startEnd.add(getDateTimeWithNext(endTokens));
			}
		}
		else if (endTokens.length == 2){
			if (!getDateTimeWithNext(endTokens).equals(FLOATING_DEADLINE)){
				startEnd.add(getDateTimeWithNext(endTokens));
			}
			else if (getDateTimeFrom2Tokens(endTokens) == null){
				return FLOATING;
			}
			else {
				startEnd.add(getDateTimeFrom2Tokens(endTokens));
			}
		}
		else {
			String end = endTokens[0];
			DateTime result = getDateTimeFrom1Token(end);
			if(isTime(end)){
				if(!startEnd.get(0).equals(MIN_DATETIME)){
					int endHour = result.getHourOfDay();
					int endMin = result.getMinuteOfHour();
					int totalMin = endHour*60 + endMin;
					DateTime startTime = startEnd.get(0);
					int startMin = startTime.getMinuteOfDay();
					int diff = totalMin - startMin;
					DateTime endTime = startTime.plusMinutes(diff);
					startEnd.add(endTime);
				}
			}
			else if (result == null || result.equals(FLOATING_DEADLINE)) {
				return FLOATING;
			}
			else {
				startEnd.add(result);
			}
		}

		return startEnd;
	}


	private DateTime getInstantDateTime() {
		String[] splitByKeywordBY = splitByKeyword(KEYWORD_BY,userCommand);

		if (splitByKeywordBY.length > 2) {
			if (userCommand.contains(KEYWORD_BY[0])){
				return null;
			}
			else {
				return FLOATING_DEADLINE;
			}
		}
		else if (splitByKeywordBY.length == 2){ // Specific deadline
			String[] tempTokens = splitByKeywordBY[1].trim().split("\\s+");//Split date and time, ignore " "
			if (tempTokens.length > 2) {
				if(contain(tempTokens,"next")){
					return getDateTimeWithNext(tempTokens);
				}
				else {// Invalid format, it doesn't have 'next', but 3 or more tokens
					if ((contain(tempTokens, "in"))||(contain(tempTokens, "/in"))){
						String[] splitByKeywordIN = splitByKeyword(KEYWORD_IN,userCommand);
						return inFutureTime(splitByKeywordIN[1]);
					}
					return FLOATING_DEADLINE;
				}
			}
			else if (tempTokens.length == 2) { // Date + time or time + Date 
				if (contain(tempTokens,"next")){
					return getDateTimeWithNext(tempTokens);
				}
				else {
					return getDateTimeFrom2Tokens(tempTokens);
				}
			}
			else {//tempTokens.length ==1
				// Date only or time only //attention!
				String tempToken = tempTokens[0];
				return getDateTimeFrom1Token(tempToken);

			}
		}
		else {//splitByKeywordBY.length == 1 doesn't contain '/by'
			String[] splitByKeywordIn = splitByKeyword(KEYWORD_IN,userCommand);
			if (splitByKeywordIn.length == 1){
				return FLOATING_DEADLINE;
			}

			String timeSpan = splitByKeywordIn[1];
			try {   
				return inFutureTime(timeSpan);        
			}
			catch (NumberFormatException e){
				return null;
			}
		}
	}
	private void setDateTime(){
		DateTime deadline = getInstantDateTime();
		if (deadline.equals(FLOATING_DEADLINE)) {
			range = getStartEndTime();        		
		}
		else {
			range.add(deadline);
			range.add(deadline);
		}        	
	}

	private String[] splitByKeyword(String[] keyword, String cmdString){
		String[] splitByKeyword;
		if(cmdString.contains(keyword[0])){
			splitByKeyword = cmdString.split(keyword[0]);
		}
		else{
			splitByKeyword = cmdString.split(keyword[1]);
		}
		return splitByKeyword;

	}
	private boolean contain(String[] array, String word){
		for(int i = 0; i< array.length; i ++){
			if (array[i].equalsIgnoreCase(word)){
				return true;
			}
		}
		return false;
	}
	private DateTime getDateTimeWithNext(String[] tempTokens){
		String[] newTokens = removeWordNext(tempTokens);
		int numOfNext = tempTokens.length - newTokens.length;
		DateTime now = DateTime.now();
		if (newTokens.length == 1){//remove "next", only the weekday left(or others)
			String token = newTokens[0];
			DateTime afterWeeks;
			if (getDateFromWeekday(token) == null){
				return FLOATING_DEADLINE;
			}
			else{
				afterWeeks = getDateTimeFrom1Token(token);
			}
			if (afterWeeks.getDayOfWeek()<now.getDayOfWeek()){
				numOfNext--;
			}
			for(int i = 0; i < numOfNext;i ++){
				afterWeeks = afterWeeks.plusDays(7);
			}
			return afterWeeks;
		}
		else if (newTokens.length == 2){
			DateTime afterWeeks;
			if (getDateTimeFrom2Tokens(newTokens) == null){
				return FLOATING_DEADLINE;
			}
			else {
				afterWeeks = getDateTimeFrom2Tokens(newTokens);
			}
			if (afterWeeks.getDayOfWeek()<now.getDayOfWeek()){
				numOfNext--;
			}
			for(int i = 0; i < numOfNext;i ++){
				afterWeeks = afterWeeks.plusDays(7);
			}
			return afterWeeks;
		}
		else {
			return FLOATING_DEADLINE;
		}
	}
	public boolean isDate(String dateString){
		if (dateArgs(dateString) != null){
			return true;
		}
		else {
			return false;
		}
	}
	public boolean isTime(String timeString){
		if (timeArgs(timeString) != null){
			return true;
		}
		else {
			return false;
		}
	}
	private DateTime getDateTimeFrom1Token(String tempToken){
		//token is either date or time

		if (isDate(tempToken)){
			onlyDate = true;
			Vector<Integer> dateArguments = dateArgs(tempToken);
			try {
				int year        = dateArguments.get(0), 
						month   = dateArguments.get(1), 
						day     = dateArguments.get(2);
				DateTime dateTime = new DateTime(year,month,day,23,59,0,0);

				return dateTime;

			} catch (NullPointerException e) {
				return null;
			}
		}
		else if (isTime(tempToken)){
			Vector<Integer> timeArguments = timeArgs(tempToken);
			try {
				int year        = DateTime.now().getYear(),
						month = DateTime.now().getMonthOfYear(),
						day     = DateTime.now().getDayOfMonth(),
						hour    = timeArguments.get(0),
						minute  = timeArguments.get(1);
				DateTime then = new DateTime(year,month,day,hour,minute,0,0);
				if (then.isBeforeNow()){
					then = then.plusDays(1);
				}
				return then;

			} catch (NullPointerException e) {
				return null;
			}
		}
		else{
			return FLOATING_DEADLINE;
		}

	}
	private DateTime getDateTimeFrom2Tokens(String[] tempTokens){
		//tokens are date and time without order limit
		Vector <Integer> dateArguments = null;//store the date information temply
		if (isDate(tempTokens[0])){
			dateArguments = dateArgs(tempTokens[0]); //D+T
		}
		else if(isDate(tempTokens[1])) {
			dateArguments = dateArgs(tempTokens[1]); //T+D
		}
		else {
			return FLOATING_DEADLINE;
		}

		Vector <Integer> timeArguments = null;//store the time information temply
		if (isTime(tempTokens[0])){
			timeArguments = timeArgs(tempTokens[0]); //T+D
		}
		else if(isTime(tempTokens[1])) {
			timeArguments = timeArgs(tempTokens[1]); //D+T
		}
		else {

		}

		try {
			int year        = dateArguments.get(0), 
					month   = dateArguments.get(1), 
					day     = dateArguments.get(2),
					hour    = timeArguments.get(0), 
					minute  = timeArguments.get(1);

			DateTime then = new DateTime(year,month,day,hour,minute,0,0);
			return then;
		} catch (NullPointerException e) {
			return null;
		}
	}
	private String[] removeWordNext(String[] input) {
		int length = input.length;
		String wordNext ="next";
		Vector<String> temp = new Vector<String>(); 
		for(int i = 0;i<length;i ++){
			if (!input[i].equalsIgnoreCase(wordNext)){
				temp.add(input[i]);
			}
		}
		String[] newArray = temp.toArray(new String[temp.size()]);
		return newArray;
	}

	private DateTime inFutureTime(String timeSpan){
		DateTime now = DateTime.now();
		DateTime then = now;
		String[] arguments = timeSpan.split(" ");
		try {
			for (int i = 0; i < arguments.length; i++) {
				if (arguments[i].equalsIgnoreCase("sec") || 
					arguments[i].equalsIgnoreCase("second") || 
					arguments[i].equalsIgnoreCase("seconds")) {
					int inSeconds = Integer.parseInt(arguments[i-1]);
					then = then.plusSeconds(inSeconds);
				}
				if (arguments[i].equalsIgnoreCase("min") || 
					arguments[i].equalsIgnoreCase("minute") || 
					arguments[i].equalsIgnoreCase("minutes")) {
					int inMinutes = Integer.parseInt(arguments[i-1]);
					then = then.plusMinutes(inMinutes);
				}
				if (arguments[i].equalsIgnoreCase("hr") || 
					arguments[i].equalsIgnoreCase("hour") || 
					arguments[i].equalsIgnoreCase("hours")) {
					int inHours = Integer.parseInt(arguments[i-1]);
					then = then.plusHours(inHours);
				}
				if (arguments[i].equalsIgnoreCase("day") || 
					arguments[i].equalsIgnoreCase("days")) {
					int inDays = Integer.parseInt(arguments[i-1]);
					then = then.plusDays(inDays);
				}
				if (arguments[i].equalsIgnoreCase("wk") || 
					arguments[i].equalsIgnoreCase("week") || 
					arguments[i].equalsIgnoreCase("weeks")) {
					int inWeeks = Integer.parseInt(arguments[i-1]);
					then = then.plusWeeks(inWeeks);
				}
				if (arguments[i].equalsIgnoreCase("mth") || 
					arguments[i].equalsIgnoreCase("month") || 
					arguments[i].equalsIgnoreCase("months")) {
					int inMonths = Integer.parseInt(arguments[i-1]);
					then = then.plusMonths(inMonths);
				}
				if (arguments[i].equalsIgnoreCase("yr") || 
					arguments[i].equalsIgnoreCase("year") || 
					arguments[i].equalsIgnoreCase("years")) {
					int inYears = Integer.parseInt(arguments[i-1]);
					then = then.plusYears(inYears);
				}
			}
		} catch (NumberFormatException e) {
			return null;
		} catch (ArrayIndexOutOfBoundsException e) {
			return null;
		}
		if (then.equals(now)){
			return FLOATING_DEADLINE;
		} // it means that the string doesn't contain any keyword above
		return then;
	}

	private Vector <Integer> dateArgs(String dateString) {
		//this method checks 3 kinds of date: weekday, today/tmr and / /
		Vector <Integer> dateArguments = new Vector <Integer> ();
		DateTime today = DateTime.now();
		dateString = dateString.trim();
		Vector<Integer> dateFromWeekday = getDateFromWeekday(dateString);
		if(!(dateFromWeekday == null)){
			return dateFromWeekday; 
		}// it's week day
		for(int i = 0;i < TODAY_OR_TMR.length; i++){
			if (dateString.equalsIgnoreCase(TODAY_OR_TMR[i])){
				int dateDifference;
				if (i == 0){
					dateDifference = 0;
				}
				else{
					dateDifference = 1;
				}


				DateTime taskDate = today.plusDays(dateDifference);

				// return vector containing year,month,day
				dateArguments.add(taskDate.year().get());
				dateArguments.add(taskDate.monthOfYear().get());
				dateArguments.add(taskDate.dayOfMonth().get());
				return dateArguments;

			}
		}//it's today or tomorrow

		String[] splitBySlash = dateString.split("/");
		if (splitBySlash.length != 3) {
			if(splitBySlash.length == 2){//without the year
				int day = Integer.parseInt(splitBySlash[0]);
				int month = Integer.parseInt(splitBySlash[1]);
				int year = DateTime.now().getYear();
				if (isDateValid(year,month,day)){
					dateArguments.add(year);
					dateArguments.add(month);
					dateArguments.add(day);
					return dateArguments;
				}
			}
			else {//splitBySlash.length == 1, not a valid date format
				return null;
			}
		} else try {//splitBySlash.length == 3
			int year        = Integer.parseInt(splitBySlash[2]),
					month   = Integer.parseInt(splitBySlash[1]),
					day             = Integer.parseInt(splitBySlash[0]);
			if(!isDateValid(year,month,day)){//check if the date number is valid
				return null;
			}

			dateArguments.add(year);
			dateArguments.add(month);
			dateArguments.add(day);
			return dateArguments; // return vector containing year,month,day
		} catch (NumberFormatException e) {
			return null;
		}// it's date with slash( / / )
		return dateArguments;
	}
	private Vector <Integer> getDateFromWeekday(String dateString){
		Vector <Integer> dateArguments = new Vector <Integer> ();
		DateTime today = DateTime.now();
		int todayDate = today.dayOfWeek().get();
		for (int i = 0; i < NUM_WEEKDAY; i++) {
			if (dateString.equalsIgnoreCase(DAYS_OF_WEEK[i])) {
				// get offset
				int dateDifference = ((i%7)+1 - todayDate >= 0 ? (i%7)+1 - todayDate : (i%7)+1 - todayDate + 7);
				DateTime taskDate = today.plusDays(dateDifference);

				// return vector containing year,month,day
				dateArguments.add(taskDate.year().get());
				dateArguments.add(taskDate.monthOfYear().get());
				dateArguments.add(taskDate.dayOfMonth().get());
				return dateArguments;
			}
		}
		return null;
	}
	private boolean isDateValid(int year, int month, int day){
		//check if the date number is valid
		if(year < 1970) return false;
		if(month < 1 || month > 12) {
			return false;
		}
		int[] MonthDays = {31,28,31,30,31,30,31,31,30,31,30,31};
		boolean isLeapYear = false;
		if(((year % 4 == 0) && (year % 100 != 0))|| (year % 400 == 0)){
			isLeapYear = true;
		}
		if(isLeapYear){
			MonthDays[1]=29;
		}
		if(day < 1 || day > MonthDays[month-1] ) {
			return false;
		}

		return true;
	}

	private Vector <Integer> timeArgs(String timeString) {
		// this method checks 3 kinds of time: time with colon( : ), am/pm, and both(like 2:00pm)
		Vector <Integer> timeArguments = new Vector <Integer> ();
		timeString = timeString.trim();
		String[] splitByColon = timeString.split(":");
		if (splitByColon.length != 2) {//if the format is not xx:xx
			if(timeString.contains("am")){
				int amIndex = timeString.indexOf("am");
				int hour = Integer.parseInt(timeString.substring(0, amIndex));
				if (hour == 12){
					hour = 0;
				}//because 12 am equals 0am
				if((hour<0)||(hour>12)){
					return null;
				}
				timeArguments.add(hour);
				timeArguments.add(0);
				return timeArguments;
			}
			else if(timeString.contains("pm")){
				int pmIndex = timeString.indexOf("pm");
				int hour = Integer.parseInt(timeString.substring(0, pmIndex));
				if((hour<1)||(hour>12)){
					return null;
				}
				if (hour == 12){
					hour = 0;
				}//because 12pm equals 0pm
				timeArguments.add(12 + hour);
				timeArguments.add(0);
				return timeArguments;
			}
			else{//not either format
				return null;
			}
		} else try {//splitByColon.length == 2,meaning current format is xx:xx
			int hour        = Integer.parseInt(splitByColon[0]),
					minute  = Integer.parseInt(splitByColon[1]);

			timeArguments.add(hour);
			timeArguments.add(minute);
			return timeArguments;// return vector containing hour,minute
		} catch (NumberFormatException e) { //check if timeString=='4:00 pm'
			if (splitByColon[1].contains("am")){
				int hour        = Integer.parseInt(splitByColon[0]),
						minute  = Integer.parseInt(splitByColon[1].substring(0,2));     
				if (hour == 12){
					hour = 0;
				}
				if((hour<0)||(hour>12)){
					return null;
				}       
				timeArguments.add(hour);
				timeArguments.add(minute);
				return timeArguments; // return vector containing hour,minute
			}
			else if (splitByColon[1].contains("pm")){
				int hour        = Integer.parseInt(splitByColon[0]),
						minute  = Integer.parseInt(splitByColon[1].substring(0,2));     
				if((hour<1)||(hour>12)){
					return null;
				}
				if (hour == 12){
					hour = 0;
				}       
				timeArguments.add(12 + hour);
				timeArguments.add(minute);
				return timeArguments; // return vector containing hour,minute
			}
			return null;
		}
	}
	public boolean searchOnlyDate() {
		return onlyDate;
	}
}

